#include <Precomp.h>
#include <AVUIINotifyPropertyChanged.h>
#include <AVUIListView.h>
#include <AVUIItemCollection.h>
#include "defs.h"
#include "GameWorld.h"
#include "GamePlayerList.h"
#include "Player.h"

using namespace AVUI;

struct EnumToStringMapping
{
    const char* szName;
};

const EnumToStringMapping c_rgShipNames[] =
{
    { "SC" },
    { "DD" },
    { "CA" },
    { "BB" },
    { "AS" },
    { "SB" },
    { "GA" },
    { "AT" },
};
// NEED COMPILE TIME ASSERT FOR THIS TABLE LENGTH

const EnumToStringMapping c_rgRank[] =
{
    { "Esgn" },
    { "Lt" },
    { "LtCm" },
    { "Cder" },
    { "Capt" },
    { "FltC" },
    { "Cdor" },
    { "RAdm" },
    { "Admr" },
};


class PlayerEntry : public EventableObject, public INotifyPropertyChanged
{
public:
    PlayerEntry(CGamePlayer* pPlayer) : m_pPlayer(pPlayer)
    {
    }

    const char* get_Identifier() { return m_pPlayer->GetIdentifier(); }
    int get_ShipType() { return m_pPlayer->GetShipData()->GetShipType(); }
    int get_TeamID() { return m_pPlayer->GetTeamID(); }
    int get_Rank() { return m_pPlayer->GetRank(); }
    const char* get_Name() { return m_pPlayer->GetPlayerName(); }
    float get_Kills() { return m_pPlayer->GetKills(); }
    float get_Wins() { return 0.0f; }
    float get_Losses() { return 0.0f; }
    float get_Ratio() { return 0.0f; }
    float get_Offense() { return 0.0f; }
    float get_Defense() { return 0.0f; }
    float get_DamageInflicted() { return 0.0f; }

    DECLARE_ELEMENT(PlayerEntry, Object);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Identifier, const char*, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(ShipType, int, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(TeamID, int, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Rank, int, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Name, const char*, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Kills, float, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Wins, float, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Losses, float, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Ratio, float, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Offense, float, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Defense, float, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(DamageInflicted, float, false);

    IMPLEMENT_EVENT(PropertyChanged, PropertyChangedEventArgs);

    CGamePlayer* get_Player() { return m_pPlayer; }

    void NotifyPropertyChanged(Property* pProperty)
    {
        PropertyChangedEventArgs args(pProperty);

        invoke_PropertyChanged(this, &args);
    }

    Object* get_Object() { return this; }

private:

    CGamePlayer* m_pPlayer;
};

REGISTER_ELEMENT_BEGIN(PlayerEntry)
    REGISTER_INTERFACE(INotifyPropertyChanged);
    REGISTER_PROPERTY(Identifier);
    REGISTER_PROPERTY(ShipType);
    REGISTER_PROPERTY(TeamID);
    REGISTER_PROPERTY(Rank);
    REGISTER_PROPERTY(Name);
    REGISTER_PROPERTY(Kills);
    REGISTER_PROPERTY(Wins);
    REGISTER_PROPERTY(Losses);
    REGISTER_PROPERTY(Ratio);
    REGISTER_PROPERTY(Offense);
    REGISTER_PROPERTY(Defense);
    REGISTER_PROPERTY(DamageInflicted);
REGISTER_ELEMENT_END()


CGamePlayerList::CGamePlayerList(CGameWorld* pGameWorld, ListView* pList) : m_pGameWorld(pGameWorld), m_pList(pList)
{
    CPlayerList& playerList = m_pGameWorld->GetPlayerList();

    for(CPlayerList::iterator i = playerList.begin(); i < playerList.end(); ++i)
    {
        UpdateRowForPlayer(*i);
    }

    m_pEventSubscription = pGameWorld->SubscribeEvents( CGameWorld::EventSubscriber(&CGamePlayerList::OnGameWorldEvent, this));
}

void CGamePlayerList::OnGameWorldEvent(CGameWorldEvent* pGameWorldEvent)
{
    if(pGameWorldEvent->GetEventID() != eGameWorldEventID_PlayerStatsUpdated)
    {
        return;
    }

    CPlayerEvent* pPlayerUpdated = (CPlayerEvent*) pGameWorldEvent;
    CGamePlayer* pPlayer = pPlayerUpdated->GetPlayer();

    UpdateRowForPlayer(pPlayer);
}

CGamePlayerList::~CGamePlayerList() 
{
    m_pGameWorld->UnsubscribeEvents(m_pEventSubscription);
}

PlayerEntry* CGamePlayerList::GetEntryForPlayer(CGamePlayer* pPlayer)
{
    for(int i = 0; i < m_pList->get_Items()->get_Count(); i++)
    {
        PlayerEntry* pPlayerEntry = object_cast<PlayerEntry>(m_pList->get_Items()->GetItemAt(i));

        if(pPlayerEntry->get_Player() == pPlayer)
        {
            return pPlayerEntry;
        }
    }
    return NULL;
}

PlayerEntry* CGamePlayerList::AddRowForPlayer(CGamePlayer* pPlayer)
{
    TRefCountedPtr<PlayerEntry> pEntry = object_allocate<PlayerEntry>(pPlayer);

    m_pList->get_Items()->Add(pEntry);

    return pEntry;
}

void CGamePlayerList::UpdateRowForPlayer(CGamePlayer* pPlayer)
{
    TRefCountedPtr<PlayerEntry> pEntry = GetEntryForPlayer(pPlayer);

    if(pEntry == NULL)
    {
        if(pPlayer->GetPlayerStatus() == ePlayerStatus_SlotFree)
        {
            return;
        }

        pEntry = AddRowForPlayer(pPlayer);       
    }

    if(pPlayer->GetPlayerStatus() == ePlayerStatus_SlotFree)
    {
        m_pList->get_Items()->Remove(pEntry);

        return;
    }

    pEntry->NotifyPropertyChanged(PlayerEntry::get_IdentifierProperty());
    pEntry->NotifyPropertyChanged(PlayerEntry::get_RankProperty());
    pEntry->NotifyPropertyChanged(PlayerEntry::get_NameProperty());
    pEntry->NotifyPropertyChanged(PlayerEntry::get_KillsProperty());
    pEntry->NotifyPropertyChanged(PlayerEntry::get_TeamIDProperty());
}


